﻿#include <sstream>
#include <CXXLCOMPOSITE.HPP>
#include <CXXLWCSPBRK.HPP>

using namespace std;
using namespace CxxlMan;


class TxtBuild
{
  wostream &S;       // 存放轉換結果

  unsigned int Tab; // 縮排層級數

  void cxxlFASTCALL toTab()
  {
    for(unsigned int i = 0, j = Tab * 2; i < j; ++i)
      S << L' ';
  }

  UNICODE_String cxxlFASTCALL NormalName(const wchar_t *Name)
  {
    static const wchar_t *Sh[] = {L"&",L"]",L"\n",L"\r",NULL};
    static const wchar_t *Rp[] = {L"&#38;",L"&#93;",L"&#10;",L"&#13;",NULL};
    return cxxlWcsReplace(Name,Sh,Rp);
  }

  UNICODE_String cxxlFASTCALL NormalValue(const wchar_t *Value)
  {
    static const wchar_t *Sh[] = {L"&",L"\"",L"\n",L"\r",NULL};
    static const wchar_t *Rp[] = {L"&#38;",L"&#34;",L"&#10;",L"&#13;",NULL};
    return cxxlWcsReplace(Value,Sh,Rp);
  }

public:
  // Constructor
  TxtBuild(wostream &wout)
    :S(wout)
  {
    Tab = 0;
  }

  // Destructor
  ~TxtBuild()
  {
  }

  void cxxlFASTCALL NewNode(const UNICODE_String &NodeName)
  {
    S << endl;
    toTab();
    S << '[' << (const wchar_t*)NormalName(NodeName) << ']';
  }

  void cxxlFASTCALL AddValue(const UNICODE_String &Value)
  {
    S << L'=' << L'"' << (const wchar_t*)NormalValue(Value) << L'"';
  }

  void cxxlFASTCALL EnterNewNode()
  {
    S << endl;
    toTab();
    S << L'{'; // << endl;
    ++Tab;
  }

  void cxxlFASTCALL ReturnParentNode()
  {
    S << endl;
    --Tab;
    toTab();
    S << L'}'; // << endl;
  }
};


class TxtCompositeReader
{
  TxtBuild Builder;
public:
  // Constructor
  TxtCompositeReader(wostream &wout)
    :Builder(wout)
  {
  }

  template <typename T>
  void cv(const Smart_Ptr<T> &TxtComposite_Ptr)
  {
    Builder.NewNode(TxtComposite_Ptr->GetName());

    UNICODE_String Value = (string_wrapper<wchar_t> *)(TxtComposite_Ptr->GetObj());
    if(Value.isNULL() == false)
      Builder.AddValue(Value);

    Smart_Ptr<cxxlList<T> > TxtComposite_List = TxtComposite_Ptr->cxxlList_Create();

    unsigned long Count;
    if((Count = TxtComposite_List->GetCount()))
    {
      Builder.EnterNewNode();

      TxtComposite_List->ResetPT(toHead);
      for(Smart_Ptr<T> p = (*TxtComposite_List)++; Count > 0; p = (*TxtComposite_List)++, --Count)
        cv(p);

      Builder.ReturnParentNode();
    }
  }
};

CXXL_DLLEXPORT void cxxlFASTCALL CxxlMan::UniqueTxtCompositeExport(wostream &wout, const Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,true> > &TxtComposite)
{
  TxtCompositeReader Reader(wout);

  Reader.cv(TxtComposite);
}

CXXL_DLLEXPORT void cxxlFASTCALL CxxlMan::NonUniqueTxtCompositeExport(wostream &wout, const Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,false> > &TxtComposite)
{
  TxtCompositeReader Reader(wout);

  Reader.cv(TxtComposite);
}


/*****************************************************************************/

template <bool isUnique>
class TxtListReader:virtual public cxxlObject
{
  enum Result  {
    OK,           // 完成
    False,        // 失敗
    Escape        // 告知父節點，已截取到它的 '}'，可以離閇了
  };

  cxxlWcspbrk Wcspbrk;

  UNICODE_String cxxlFASTCALL UnNormalName(const wchar_t *Name)
  {
    static const wchar_t *Sh[] = {L"&#38;",L"&#93;",L"&#10;",L"&#13;",NULL};
    static const wchar_t *Rp[] = {L"&",L"]",L"\n",L"\r",NULL};
    return cxxlWcsReplace(Name,Sh,Rp);
  }

  UNICODE_String cxxlFASTCALL UnNormalValue(const wchar_t *Value)
  {
    static const wchar_t *Sh[] = {L"&#38;",L"&#34;",L"&#10;",L"&#13;",NULL};
    static const wchar_t *Rp[] = {L"&",L"\"",L"\n",L"\r",NULL};
    return cxxlWcsReplace(Value,Sh,Rp);
  }

public:
  // Constructor
  TxtListReader(wistream &TLC)
    :cxxlObject(Spirit_Easy), Wcspbrk(new wiStream_Source(TLC))
  {
  }

  // Destructor
  ~TxtListReader()
  {
  }


  Result cxxlFASTCALL NewNode(const Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,isUnique> > &Parent_Ptr)
  {
    while(true)
    {
      cxxlWcspbrk_Result R;

      {
        static const wchar_t *Sh[] = {L"]",NULL};
        R = Wcspbrk.Next(Sh);
        if(R.Token.isNULL())
          return False;
      }

      Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,isUnique> > Node_Ptr = Parent_Ptr->Add(NULL,UnNormalName((const wchar_t*)R.SubStr));
      if(Node_Ptr.isNULL())
        return False;

      {
        static const wchar_t *Sh[] = {L"\"",L"{",L"[",L"}",NULL};
        R = Wcspbrk.Next(Sh);
      }

      if(R.Token.isNULL())
        return False;

      if(*(const wchar_t*)(R.Token) == L'"')
      {
        static const wchar_t *Sh[] = {L"\"",NULL};
        R = Wcspbrk.Next(Sh);

        if(R.Token.isNULL())
          return False;

        Node_Ptr->SetObj(UnNormalValue((const wchar_t*)R.SubStr));
        {
          static const wchar_t *Sh[] = {L"{",L"[",L"}",NULL};
          R = Wcspbrk.Next(Sh);
        }
      }

      if(*(const wchar_t*)(R.Token) == L'{')
      {
        while(true)
        {
          cxxlWcspbrk_Result R;
          {
            static const wchar_t *Sh[] = {L"[",L"}",NULL};
            R = Wcspbrk.Next(Sh);
          }

          if(R.Token.isNULL())
            return False;

          if(*(const wchar_t*)R.Token == L'[')
          {
            Result result = NewNode(Node_Ptr);
            if(result == Escape)
              return OK;
            else if(result == False)
              return False;
          }
          else
            return OK;
        }
      }
      else if(*(const wchar_t*)R.Token == L'}')
      {
        return Escape;
      }
    }
  }

  Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,isUnique> > cxxlFASTCALL Start(const Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,isUnique> > &tempTxtComposite_Arg)
  {
    {
      static const wchar_t *Sh[] = {L"[",NULL};

      cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);

      if(R.Token.isNULL())
        return NULL;
    }

    if(NewNode(tempTxtComposite_Arg) == False)
      return NULL;

    Smart_Ptr<cxxlList<cxxlComposite<string_wrapper<wchar_t>,isUnique> > > TxtComposite_List =
      tempTxtComposite_Arg->cxxlList_Create();

    if(TxtComposite_List->GetCount())
    {
      TxtComposite_List->ResetPT(toHead);
      return TxtComposite_List->GetObj();
    }
    else
      return NULL;
  }
};


// 匯入 建立 包裹 UNICODE 字串 名稱不可重複的 cxxlComposite 後傳回，須藉由 tempUniqueTxtComposite_Arg 指定一個空的 cxxlComposite 樣版，將用它產生要傳回的 cxxlComposite 物件
// 須是 cxxlComposite<string_wrapper<wchar_t>,true> 或其延伸類別
// 若有錯誤回傳 NULL
CXXL_DLLEXPORT Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,true> > cxxlFASTCALL CxxlMan::UniqueTxtCompositeImport(
  std::wistream &TLC, 
  const Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,true> > &tempUniqueTxtComposite_Arg)
{
  TxtListReader<true> TLReader(TLC);

  return TLReader.Start(tempUniqueTxtComposite_Arg);
}


// 匯入 建立 包裹 UNICODE 字串 名稱可重複的 cxxlComposite 後傳回，須藉由 tempNonUniqueTxtComposite_Arg 指定一個空的 cxxlComposite 樣版，將用它產生要傳回的 cxxlComposite 物件
// 若有錯誤回傳 NULL
CXXL_DLLEXPORT Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,false> > cxxlFASTCALL CxxlMan::NonUniqueTxtCompositeImport(
  std::wistream &TLC, 
  const Smart_Ptr<cxxlComposite<string_wrapper<wchar_t>,false> > &tempNonUniqueTxtComposite_Arg)
{
  TxtListReader<false> TLReader(TLC);

  return TLReader.Start(tempNonUniqueTxtComposite_Arg);
}


